package com.hsy.swu.spider

import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.IBinder
import android.webkit.WebView
import androidx.room.Room
import com.hsy.swu.MyConfig
import com.hsy.swu.clouddb.LeanCloudHelper
import com.hsy.swu.clouddb.MyUser
import com.hsy.swu.home.course.CourseModel
import com.hsy.swu.home.exam.ExamModel
import com.hsy.swu.home.grade.GradeModel
import com.hsy.swu.home.textbook.TextbookModel
import com.hsy.swu.hsyutils.MActivityUtil
import com.hsy.swu.hsyutils.MLog
import com.hsy.swu.roomdb.AppDatabase
import com.hsy.swu.utils.RetrofitUtils
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import java.time.LocalDate
import java.util.concurrent.Executors

class SwuSpiderService : Service() {
    private lateinit var mWebView: WebView
    private val mRetrofitService =
        RetrofitUtils.getService<SwuApiService>("http://jw-swu-edu-cn.sangfor.vpn.swu.edu.cn:8118/")

    private val mCachedThreadPool = Executors.newCachedThreadPool()

    private lateinit var appDatabase: AppDatabase

    private var onGetCookieListener: ((String) -> Unit)? = null

    private var onGetCourseListener: ((List<CourseModel>) -> Unit)? = null
    private var onGetTextbookListener: ((List<TextbookModel>) -> Unit)? = null
    private var onGetExamListener: ((List<ExamModel>) -> Unit)? = null
    private var onGetGradeListener: (() -> Unit)? = null

    fun setGetCourseListener(listener: (List<CourseModel>) -> Unit) {
        onGetCourseListener = listener
    }

    fun setGetTextbookListener(listener: (List<TextbookModel>) -> Unit) {
        onGetTextbookListener = listener
    }

    fun setGetExamListener(listener: (List<ExamModel>) -> Unit) {
        onGetExamListener = listener
    }

    fun setGetGradeListener(listener: () -> Unit) {
        onGetGradeListener = listener
    }

    inner class SwuSpiderBinder : Binder() {
        fun getService(): SwuSpiderService {
            return this@SwuSpiderService
        }
    }

    override fun onCreate() {
        super.onCreate()
        mWebView = WebView(this)

        appDatabase = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java,
            "swu"
        ).build()
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        MLog.attention("onStartCommand")

        val rAccount = intent?.getStringExtra("account")
        val rPassword = intent?.getStringExtra("password")

        val cookie = intent?.getStringExtra("Cookie") ?: ""

        getCourse(rAccount ?: MyUser.currentUser.account, cookie)

        if (!rAccount.isNullOrEmpty() && rAccount != MyUser.currentUser.account
            && !rPassword.isNullOrEmpty() && rPassword != MyUser.currentUser.password
        ) return super.onStartCommand(intent, flags, startId)

        getTextbook(cookie)
        getExam(cookie)
        getGrade(cookie) {
            onGetGradeListener?.invoke()
        }

        MActivityUtil.showToast("数据已更新")
        return super.onStartCommand(intent, flags, startId)
    }

    override fun onBind(intent: Intent?): IBinder {
        return SwuSpiderBinder()
    }

    private fun getCourse(account: String, cookie: String) {
        mCachedThreadPool.execute {
            try {
                val response = mRetrofitService.courseList(
                    cookie,
                    VariableQueryParameters.XNM,
                    VariableQueryParameters.XQM
                ).execute()
                if (response.isSuccessful) {
                    val courseList = response.body()?.kbList ?: return@execute
                    val xsxx = response.body()?.xsxx ?: return@execute
                    courseList.forEach {
                        it.account = xsxx.account
                    }
                    appDatabase.courseDao().apply {
                        deleteAllByAccount(account)
                        insertAll(courseList)
                    }
                    onGetCourseListener?.invoke(courseList)

                    // 获取名字
                    if (MyUser.currentUser.account != "" && xsxx.account == MyUser.currentUser.account) {
                        if (MyUser.currentUser.nickName == "") {
                            MyUser.currentUser.nickName = xsxx.name
                            MyUser.currentUser.writeFirst4ToSp(
                                applicationContext,
                                MyUser.USER_INFO
                            )
                            LeanCloudHelper.getInstance()?.updateObjectInBackground(
                                "MyUser",
                                MyUser.currentUser.objectId,
                                { MLog.attention("nickName更新失败：$it") },
                                { it.put("nickName", MyUser.currentUser.nickName) }
                            )
                        }
                    }
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun getTextbook(cookie: String) {
        mCachedThreadPool.execute {
            try {
                val response = mRetrofitService.textBookList(
                    cookie,
                    VariableQueryParameters.XNM,
                    VariableQueryParameters.XQM
                ).execute()
                if (response.isSuccessful) {
                    if (response.body()?.items.isNullOrEmpty()) return@execute
                    val textbookList =
                        response.body()?.items!!.subList(0, (response.body()?.items!!.size) - 1)
                    appDatabase.textbookDao().apply {
                        deleteAll()
                        insertAll(TextbookModel.sortTextbookList(textbookList))
                    }
                    onGetTextbookListener?.invoke(textbookList)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun getExam(cookie: String) {
        mCachedThreadPool.execute {
            try {
                val response = mRetrofitService.examList(
                    cookie,
                    VariableQueryParameters.XNM,
                    VariableQueryParameters.XQM
                ).execute()
                if (response.isSuccessful) {
                    response.body()?.items ?: return@execute
                    appDatabase.examDao().apply {
                        deleteAll()
                        insertAll(
                            response.body()?.items!!.onEach {
                                it.date = it.kssj.substring(0, 10)
                                it.time = it.kssj.substring(10)
                            }
                        )
                    }
                    onGetExamListener?.invoke(
                        response.body()?.items!!.onEach {
                            it.date = it.kssj.substring(0, 10)
                            it.time = it.kssj.substring(10)
                        }
                    )
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun getGrade(cookie: String, onGotEnd: () -> Unit) {
        mCachedThreadPool.execute {
            MLog.s("getGrade")
            val year = LocalDate.now().year.toString()

            var simpleGradeString: String
            var detailGradeString: String
            val getCourseStartTime = System.currentTimeMillis() // todo --- 爬成绩开始时间
            val client = OkHttpClient()

            for (i in year.toInt() downTo MyConfig.gradeYear) {
                repeat(3) {
                    MLog.s("循环爬成绩 -> $i    $it")
                    val _year = "$i"
                    val _semester = when (it) {
                        0 -> "3"
                        2 -> "12"
                        else -> "16"
                    }
                    val formBody = FormBody.Builder()
                        .add("xnm", _year)
                        .add("xqm", _semester)
                        .add("queryModel.showCount", "99")
                        .build()
                    val gradeRequest = Request.Builder()
                        .header("Cookie", cookie)
                        .url(vpnGradeUrl)
                        .post(formBody)
                        .build()
                    try {
                        val gradeResponse = client.newCall(gradeRequest).execute()
                        if (gradeResponse.isSuccessful) {
                            MLog.s("爬成绩耗时 -> ${System.currentTimeMillis() - getCourseStartTime}")
                            simpleGradeString = gradeResponse.body?.string() ?: ""
                            // 获取成绩明细
                            val gradeDetailRequest = Request.Builder()
                                .header("Cookie", cookie)
                                .url(vpnGradeDetailUrl)
                                .post(formBody)
                                .build()
                            val gradeDetailResponse =
                                client.newCall(gradeDetailRequest).execute()
                            if (gradeDetailResponse.isSuccessful) {
                                detailGradeString = gradeDetailResponse.body?.string() ?: ""
                                val gradeList = GradeModel.mergeDetailToGradeList(
                                    simpleGradeString,
                                    detailGradeString
                                )
                                if (gradeList.isEmpty()) {
                                    return@repeat
                                }
                                mCachedThreadPool.execute {
                                    appDatabase.gradeDao().apply {
                                        deleteAllByYearAndSemester(_year, _semester)
                                        insertAll(gradeList)
                                    }
                                }
                                MLog.v("成绩 $_year $_semester 获取成功 >>> ${gradeList.size}")
                                if (_year <= year && gradeList.isNotEmpty()) {
                                    onGotEnd()  // 回调更新界面
                                }
                            } else {
                                MLog.s("gradeDetailRequest error -> ${gradeDetailResponse.code}")
                                onGotEnd()
                            }
                        } else {
                            MLog.s("gradeRequest error -> ${gradeResponse.code}")
                            onGotEnd()
                        }
                    } catch (e: Exception) {
                        MLog.s(e.toString())
                        onGotEnd()
                    }
                }
            }
        }
    }
}